package com.filetransfer.util;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.filetransfer.model.entity.Device;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import java.io.IOException;
import java.net.*;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

/**
 * 设备发现工具类
 */
@Slf4j
@Component
public class DeviceDiscoveryUtil {

    /**
     * UDP广播端口
     */
    private static final int BROADCAST_PORT = 9876;
    
    /**
     * 广播地址
     */
    private static final String BROADCAST_IP = "255.255.255.255";
    
    /**
     * 发现的设备缓存
     */
    private final ConcurrentMap<String, Device> discoveredDevices = new ConcurrentHashMap<>();
    
    /**
     * 接收线程
     */
    private Thread receiverThread;
    
    /**
     * 是否运行
     */
    private volatile boolean isRunning = false;
    
    /**
     * JSON序列化工具
     */
    private final ObjectMapper objectMapper = new ObjectMapper();
    
    /**
     * 初始化
     */
    @PostConstruct
    public void init() {
        startReceiver();
    }
    
    /**
     * 销毁
     */
    @PreDestroy
    public void destroy() {
        stopReceiver();
    }
    
    /**
     * 发现设备（广播）
     * @return 发现的设备列表
     */
    public List<Device> discoverDevices() {
        try {
            // 广播设备信息
            broadcastDeviceInfo();
            
            // 等待接收设备响应
            Thread.sleep(2000);
            
            // 返回发现的设备列表
            return new ArrayList<>(discoveredDevices.values());
        } catch (Exception e) {
            log.error("设备发现失败: {}", e.getMessage());
            return new ArrayList<>();
        }
    }
    
    /**
     * 广播设备信息
     */
    public void broadcastDeviceInfo() throws IOException {
        try (DatagramSocket socket = new DatagramSocket()) {
            socket.setBroadcast(true);
            
            // 获取本机IP地址
            InetAddress localAddress = getLocalAddress();
            if (localAddress == null) {
                log.error("无法获取本机IP地址");
                return;
            }
            
            // 创建设备信息
            Device device = Device.builder()
                    .id(getDeviceId())
                    .deviceName(getDeviceName())
                    .ipAddress(localAddress.getHostAddress())
                    .status(1)
                    .lastSeen(LocalDateTime.now())
                    .build();
            
            // 序列化为JSON
            String json = objectMapper.writeValueAsString(device);
            byte[] sendData = json.getBytes();
            
            // 发送广播
            InetAddress broadcastAddress = InetAddress.getByName(BROADCAST_IP);
            DatagramPacket sendPacket = new DatagramPacket(
                    sendData,
                    sendData.length,
                    broadcastAddress,
                    BROADCAST_PORT
            );
            
            socket.send(sendPacket);
            log.info("已广播设备信息: {}", json);
        }
    }
    
    /**
     * 启动接收器
     */
    private void startReceiver() {
        if (isRunning) {
            return;
        }
        
        isRunning = true;
        receiverThread = new Thread(this::receiveLoop);
        receiverThread.setDaemon(true);
        receiverThread.start();
        log.info("设备发现接收器已启动");
    }
    
    /**
     * 停止接收器
     */
    private void stopReceiver() {
        isRunning = false;
        if (receiverThread != null) {
            receiverThread.interrupt();
            receiverThread = null;
        }
        log.info("设备发现接收器已停止");
    }
    
    /**
     * 接收循环
     */
    private void receiveLoop() {
        try (DatagramSocket socket = new DatagramSocket(BROADCAST_PORT)) {
            socket.setBroadcast(true);
            
            while (isRunning) {
                try {
                    byte[] receiveData = new byte[1024];
                    DatagramPacket receivePacket = new DatagramPacket(receiveData, receiveData.length);
                    
                    socket.receive(receivePacket);
                    
                    String json = new String(receivePacket.getData(), 0, receivePacket.getLength());
                    Device device = objectMapper.readValue(json, Device.class);
                    
                    // 添加到发现的设备缓存
                    discoveredDevices.put(device.getId(), device);
                    log.info("已接收设备信息: {}", json);
                } catch (Exception e) {
                    if (!isRunning) {
                        break;
                    }
                    log.error("接收设备信息失败: {}", e.getMessage());
                }
            }
        } catch (SocketException e) {
            log.error("设备发现接收器绑定端口失败: {}", e.getMessage());
        }
    }
    
    /**
     * 获取设备ID
     * 这里简单使用主机名，实际项目中应该使用更可靠的方式生成唯一标识
     */
    private String getDeviceId() {
        try {
            return InetAddress.getLocalHost().getHostName() + "-" + System.currentTimeMillis();
        } catch (UnknownHostException e) {
            return "unknown-" + System.currentTimeMillis();
        }
    }
    
    /**
     * 获取设备名称
     */
    private String getDeviceName() {
        try {
            return InetAddress.getLocalHost().getHostName();
        } catch (UnknownHostException e) {
            return "未知设备";
        }
    }
    
    /**
     * 获取本机IP地址
     */
    private InetAddress getLocalAddress() {
        try {
            Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces();
            while (interfaces.hasMoreElements()) {
                NetworkInterface networkInterface = interfaces.nextElement();
                if (networkInterface.isLoopback() || !networkInterface.isUp()) {
                    continue;
                }
                
                Enumeration<InetAddress> addresses = networkInterface.getInetAddresses();
                while (addresses.hasMoreElements()) {
                    InetAddress address = addresses.nextElement();
                    if (address instanceof Inet4Address) {
                        return address;
                    }
                }
            }
        } catch (SocketException e) {
            log.error("获取本机IP地址失败: {}", e.getMessage());
        }
        
        try {
            return InetAddress.getLocalHost();
        } catch (UnknownHostException e) {
            log.error("获取本机IP地址失败: {}", e.getMessage());
            return null;
        }
    }
} 